"""
历史市场数据模块
获取OKX历史市场数据
"""
import time
from typing import Dict, List, Optional
from datetime import datetime, timedelta
from loguru import logger

try:
    import okx.PublicData as PublicData
except ImportError:
    logger.warning("okx SDK未安装，请运行: pip install okx")
    PublicData = None


class MarketDataHistoryManager:
    """历史市场数据管理器"""
    
    # 限速配置：5次/2s
    RATE_LIMIT_REQUESTS = 5
    RATE_LIMIT_WINDOW = 2.0  # 秒
    
    # 数据模块类型
    MODULE_TYPES = {
        "1": "交易历史 (Trades)",
        "2": "K线数据 (Candlesticks)",
        "3": "资金费率 (Funding Rate)",
        "4": "订单簿 (Order Book)",
    }
    
    def __init__(self, sandbox: bool = True):
        """
        初始化历史市场数据管理器
        
        Args:
            sandbox: 是否使用模拟盘，True=模拟盘(1)，False=实盘(0)
        """
        if PublicData is None:
            raise ImportError("okx SDK未安装，请运行: pip install okx")
        
        self.sandbox = sandbox
        flag = "1" if sandbox else "0"
        
        # 初始化OKX公共数据API
        self.public_api = PublicData.PublicAPI(flag=flag)
        
        # 限速控制
        self.request_times: List[float] = []  # 请求时间戳列表
        
        # 数据缓存
        self.history_cache: Dict[str, List[Dict]] = {}  # cache_key -> data_list
        self.cache_expire_time: Dict[str, datetime] = {}  # cache_key -> expire_time
        self.cache_duration = timedelta(hours=24)  # 缓存24小时（历史数据不常变）
        
        logger.info(f"历史市场数据管理器已初始化 (模式: {'模拟盘' if sandbox else '实盘'})")
        logger.info("数据发布安排: 模块1/2/3通常T+2可用，订单簿数据通常T+3可用")
    
    def _check_rate_limit(self):
        """
        检查并执行限速
        限速规则：5次/2s (IP)
        """
        now = time.time()
        
        # 移除2秒前的请求记录
        self.request_times = [t for t in self.request_times 
                             if now - t < self.RATE_LIMIT_WINDOW]
        
        # 如果达到限速上限，等待
        if len(self.request_times) >= self.RATE_LIMIT_REQUESTS:
            oldest_request = self.request_times[0]
            wait_time = self.RATE_LIMIT_WINDOW - (now - oldest_request)
            
            if wait_time > 0:
                logger.debug(f"触发限速，等待 {wait_time:.2f} 秒")
                time.sleep(wait_time)
                # 重新计算
                now = time.time()
                self.request_times = [t for t in self.request_times 
                                     if now - t < self.RATE_LIMIT_WINDOW]
        
        # 记录本次请求
        self.request_times.append(now)
    
    def get_market_data_history(self, module: str, inst_id: Optional[str] = None,
                                start: Optional[str] = None, end: Optional[str] = None,
                                limit: Optional[str] = None,
                                use_cache: bool = True) -> List[Dict]:
        """
        获取历史市场数据
        
        Args:
            module: 数据模块类型
                1 = 交易历史 (Trades)
                2 = K线数据 (Candlesticks)
                3 = 资金费率 (Funding Rate)
                4 = 订单簿 (Order Book)
            inst_id: 产品ID，如 BTC-USDT-SWAP
            start: 开始时间，Unix时间戳（毫秒）
            end: 结束时间，Unix时间戳（毫秒）
            limit: 返回结果数量限制
            use_cache: 是否使用缓存
            
        Returns:
            历史数据列表，每条数据包含：
            - ts: 时间戳
            - url: 数据文件下载链接
            其他字段根据模块类型而定
        """
        # 验证模块类型
        if module not in self.MODULE_TYPES:
            raise ValueError(f"无效的模块类型: {module}，支持的类型: {list(self.MODULE_TYPES.keys())}")
        
        # 生成缓存键
        cache_key = f"{module}_{inst_id}_{start}_{end}_{limit}"
        
        # 检查缓存
        if use_cache and cache_key in self.history_cache:
            expire_time = self.cache_expire_time.get(cache_key)
            if expire_time and datetime.now() < expire_time:
                logger.debug(f"从缓存获取历史市场数据: {cache_key}")
                return self.history_cache[cache_key]
        
        # 执行限速检查
        self._check_rate_limit()
        
        try:
            # 构建请求参数
            params = {"module": module}
            if inst_id:
                params["instId"] = inst_id
            if start:
                params["start"] = start
            if end:
                params["end"] = end
            if limit:
                params["limit"] = limit
            
            module_name = self.MODULE_TYPES.get(module, "未知")
            logger.info(f"获取历史市场数据: {module_name} (模块{module})")
            if inst_id:
                logger.info(f"  产品: {inst_id}")
            
            result = self.public_api.get_market_data_history(**params)
            
            # 检查响应
            if result.get("code") != "0":
                error_msg = result.get("msg", "未知错误")
                logger.error(f"获取历史市场数据失败: {error_msg}")
                raise RuntimeError(f"API错误: {error_msg}")
            
            # 提取数据
            data_list = result.get("data", [])
            logger.info(f"获取历史市场数据成功: {len(data_list)} 条记录")
            
            # 更新缓存
            if use_cache:
                self.history_cache[cache_key] = data_list
                self.cache_expire_time[cache_key] = datetime.now() + self.cache_duration
            
            return data_list
            
        except Exception as e:
            logger.error(f"获取历史市场数据异常: {e}")
            raise
    
    def get_trades_history(self, inst_id: str, start: Optional[str] = None,
                          end: Optional[str] = None, use_cache: bool = True) -> List[Dict]:
        """
        获取交易历史数据（模块1）
        
        Args:
            inst_id: 产品ID
            start: 开始时间
            end: 结束时间
            use_cache: 是否使用缓存
            
        Returns:
            交易历史数据列表
        """
        return self.get_market_data_history(
            module="1",
            inst_id=inst_id,
            start=start,
            end=end,
            use_cache=use_cache
        )
    
    def get_candlesticks_history(self, inst_id: str, start: Optional[str] = None,
                                end: Optional[str] = None, use_cache: bool = True) -> List[Dict]:
        """
        获取K线历史数据（模块2）
        
        Args:
            inst_id: 产品ID
            start: 开始时间
            end: 结束时间
            use_cache: 是否使用缓存
            
        Returns:
            K线历史数据列表
        """
        return self.get_market_data_history(
            module="2",
            inst_id=inst_id,
            start=start,
            end=end,
            use_cache=use_cache
        )
    
    def get_funding_rate_history(self, inst_id: str, start: Optional[str] = None,
                                 end: Optional[str] = None, use_cache: bool = True) -> List[Dict]:
        """
        获取资金费率历史数据（模块3）
        
        Args:
            inst_id: 产品ID
            start: 开始时间
            end: 结束时间
            use_cache: 是否使用缓存
            
        Returns:
            资金费率历史数据列表
        """
        return self.get_market_data_history(
            module="3",
            inst_id=inst_id,
            start=start,
            end=end,
            use_cache=use_cache
        )
    
    def get_orderbook_history(self, inst_id: str, start: Optional[str] = None,
                             end: Optional[str] = None, use_cache: bool = True) -> List[Dict]:
        """
        获取订单簿历史数据（模块4）
        
        Args:
            inst_id: 产品ID
            start: 开始时间
            end: 结束时间
            use_cache: 是否使用缓存
            
        Returns:
            订单簿历史数据列表
        """
        return self.get_market_data_history(
            module="4",
            inst_id=inst_id,
            start=start,
            end=end,
            use_cache=use_cache
        )
    
    def parse_history_record(self, record: Dict) -> Dict:
        """
        解析历史数据记录
        
        Args:
            record: 原始记录
            
        Returns:
            解析后的记录字典
        """
        ts = int(record.get("ts", 0))
        
        return {
            "timestamp_ms": ts,
            "timestamp": datetime.fromtimestamp(ts / 1000).strftime("%Y-%m-%d %H:%M:%S") if ts > 0 else "",
            "url": record.get("url", ""),
            "raw_data": record,
        }
    
    def get_available_dates(self, module: str, inst_id: str) -> List[str]:
        """
        获取可用的历史数据日期列表
        
        Args:
            module: 数据模块类型
            inst_id: 产品ID
            
        Returns:
            日期列表（YYYY-MM-DD格式）
        """
        data_list = self.get_market_data_history(module, inst_id)
        
        dates = set()
        for record in data_list:
            ts = int(record.get("ts", 0))
            if ts > 0:
                date_str = datetime.fromtimestamp(ts / 1000).strftime("%Y-%m-%d")
                dates.add(date_str)
        
        return sorted(list(dates))
    
    def get_download_urls(self, module: str, inst_id: str,
                         start: Optional[str] = None,
                         end: Optional[str] = None) -> List[Dict]:
        """
        获取历史数据下载链接
        
        Args:
            module: 数据模块类型
            inst_id: 产品ID
            start: 开始时间
            end: 结束时间
            
        Returns:
            下载链接列表，每个包含时间戳和URL
        """
        data_list = self.get_market_data_history(module, inst_id, start, end)
        
        urls = []
        for record in data_list:
            parsed = self.parse_history_record(record)
            if parsed["url"]:
                urls.append({
                    "timestamp": parsed["timestamp"],
                    "url": parsed["url"],
                })
        
        return urls
    
    def get_data_summary(self, module: str, inst_id: Optional[str] = None) -> Dict:
        """
        获取历史数据摘要
        
        Args:
            module: 数据模块类型
            inst_id: 产品ID
            
        Returns:
            摘要字典
        """
        data_list = self.get_market_data_history(module, inst_id)
        
        if not data_list:
            return {
                "module": module,
                "module_name": self.MODULE_TYPES.get(module, "未知"),
                "inst_id": inst_id,
                "record_count": 0,
            }
        
        # 统计时间范围
        timestamps = [int(r.get("ts", 0)) for r in data_list if r.get("ts")]
        
        if timestamps:
            earliest = min(timestamps)
            latest = max(timestamps)
            earliest_str = datetime.fromtimestamp(earliest / 1000).strftime("%Y-%m-%d")
            latest_str = datetime.fromtimestamp(latest / 1000).strftime("%Y-%m-%d")
        else:
            earliest_str = ""
            latest_str = ""
        
        return {
            "module": module,
            "module_name": self.MODULE_TYPES.get(module, "未知"),
            "inst_id": inst_id,
            "record_count": len(data_list),
            "earliest_date": earliest_str,
            "latest_date": latest_str,
        }
    
    def clear_cache(self, module: Optional[str] = None):
        """
        清除缓存
        
        Args:
            module: 模块类型，如果为None则清除所有缓存
        """
        if module:
            # 清除指定模块的缓存
            keys_to_remove = [key for key in self.history_cache.keys() 
                            if key.startswith(f"{module}_")]
            for key in keys_to_remove:
                del self.history_cache[key]
                if key in self.cache_expire_time:
                    del self.cache_expire_time[key]
            logger.info(f"已清除模块 {module} 的缓存")
        else:
            self.history_cache.clear()
            self.cache_expire_time.clear()
            logger.info("已清除所有历史市场数据缓存")
    
    def get_cache_stats(self) -> Dict:
        """
        获取缓存统计信息
        
        Returns:
            缓存统计字典
        """
        total_cached = len(self.history_cache)
        valid_cached = sum(1 for key in self.history_cache.keys()
                          if key in self.cache_expire_time and
                          datetime.now() < self.cache_expire_time[key])
        
        return {
            "total_cached": total_cached,
            "valid_cached": valid_cached,
            "expired_cached": total_cached - valid_cached,
            "cache_duration_hours": self.cache_duration.total_seconds() / 3600,
        }


# 便捷函数
def get_trades_history(inst_id: str, sandbox: bool = True) -> List[Dict]:
    """
    便捷函数：获取交易历史数据
    
    Args:
        inst_id: 产品ID
        sandbox: 是否使用模拟盘
        
    Returns:
        交易历史数据列表
    """
    manager = MarketDataHistoryManager(sandbox=sandbox)
    return manager.get_trades_history(inst_id)


def get_candlesticks_history(inst_id: str, sandbox: bool = True) -> List[Dict]:
    """
    便捷函数：获取K线历史数据
    
    Args:
        inst_id: 产品ID
        sandbox: 是否使用模拟盘
        
    Returns:
        K线历史数据列表
    """
    manager = MarketDataHistoryManager(sandbox=sandbox)
    return manager.get_candlesticks_history(inst_id)


def get_funding_rate_history(inst_id: str, sandbox: bool = True) -> List[Dict]:
    """
    便捷函数：获取资金费率历史数据
    
    Args:
        inst_id: 产品ID
        sandbox: 是否使用模拟盘
        
    Returns:
        资金费率历史数据列表
    """
    manager = MarketDataHistoryManager(sandbox=sandbox)
    return manager.get_funding_rate_history(inst_id)


def get_orderbook_history(inst_id: str, sandbox: bool = True) -> List[Dict]:
    """
    便捷函数：获取订单簿历史数据
    
    Args:
        inst_id: 产品ID
        sandbox: 是否使用模拟盘
        
    Returns:
        订单簿历史数据列表
    """
    manager = MarketDataHistoryManager(sandbox=sandbox)
    return manager.get_orderbook_history(inst_id)
